// bdlar_symbolicconverter.h                                          -*-C++-*-
#ifndef INCLUDED_BDLAR_SYMBOLICCONVERTER_H
#define INCLUDED_BDLAR_SYMBOLICCONVERTER_H

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a utility for convert types with matching member symbols.
//
//@CLASSES:
//  bdlar::SymbolicConverter: symbolic converter utility
//
//@SEE_ALSO: bdlat_symbolicconverter
//
//@DESCRIPTION: The `bdlar::SymbolicConverter` utility provided by this
// component defines a single parameterized function `convert`.  The `convert`
// function takes two arguments: a destination and a source object.  The
// destination and source objects may be of different types.  Details about the
// used conversion rules can be found in the `bdlat_symbolicconverter`
// component description.
//
// Both `bdlat_SymbolicConverter` and `bdlar::SymbolicConverter` classes
// implement absolutely equivalent functionality and produce the same results.
// The difference in not **what** they do, but **how** they do it.  While
// `bdlat_SymbolicConverter` uses template metaprogramming and generates a lot
// of template instances, `bdlar::SymbolicConverter` doesn't generate any code
// at compile time - all the required code is pre-compiled.  It can reduce code
// bloat, compile time, and the load on the compiler in general, which can be
// benificial for large data schemas.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Usage
/// - - - - - - - - - - -
// This component can be used with types supported by the `bdlat` framework.
// In particular, types generated by the `bas_codegen.pl` tool can be used.
// For example, suppose we have the following XML schema inside a file called
// `xsdfile.xsd`:
// ```
// <?xml version='1.0' encoding='UTF-8'?>
// <xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
//            xmlns:bdem='http://bloomberg.com/schemas/bdem'
//            elementFormDefault='unqualified'>
//
//     <xs:complexType name='Employee'>
//         <xs:sequence>
//             <xs:element name='Name'   type='string'/>
//             <xs:element name='Dept'   type='string'/>
//             <xs:element name='Age'    type='int'/>
//             <xs:element name='Salary' type='float'/>
//         </xs:sequence>
//     </xs:complexType>
//
//     <xs:complexType name='Trainee'>
//         <xs:sequence>
//             <xs:element name='Name' type='string'/>
//             <xs:element name='Dept' type='string'/>
//             <xs:element name='Age'  type='int'/>
//         </xs:sequence>
//     </xs:complexType>
//
// </xs:schema>
// ```
// Using the `bas_codegen.pl` tool, we can generate C++ classes for this
// schema:
// ```
// $ bas_codegen.pl -g h -g cpp -p test xsdfile.xsd
// ```
// This tool will generate the header and implementation files for the
// `test_employee` and `test_trainee` components in the current directory.
//
// Now suppose we want to create a `hireTrainee` function, that converts a
// trainee to an employee.  Such a function could be written as follows:
// ```
// #include <test_employee.h>
// #include <test_trainee.h>
//
// #include <bdlar_symbolicconverter.h>
//
// using namespace BloombergLP;
//
// int hireTrainee(test::Employee       *result,
//                 const test::Trainee&  trainee,
//                 float                 salary)
// {
//     int retCode = bdlar::SymbolicConverter::convert(result, trainee);
//
//     result->salary() = salary;
//
//     return retCode;
// }
// ```
//  The `hireTrainee` function can be used as follows:
// ```
// void usageExample()
// {
//     test::Trainee trainee;
//
//     trainee.name() = "Bob";
//     trainee.dept() = "RnD";
//     trainee.age()  = 24;
//
//     test::Employee employee;
//
//     int result = hireTrainee(&employee, trainee, 20000.00f);
//
//     assert(0         == result);
//     assert("Bob"     == employee.name());
//     assert("RnD"     == employee.dept());
//     assert(24        == employee.age());
//     assert(20000.00f == employee.salary());
// }
// ```

#include <bslscm_version.h>

#include <bdlar_refutil.h>

#include <bsl_ostream.h>

namespace BloombergLP {
namespace bdlar {

                            // ========================
                            // struct SymbolicConverter
                            // ========================

/// This utility contains a single `convert` function that converts a value
/// from one type to another compatible type.
struct SymbolicConverter {
    // CLASS METHODS

    /// Convert the value of the specified `rhs` object to the specified
    /// (modifiable) `lhs` object.  Optionally specify an `errorStream` to
    /// print error messages.  Return 0 on success and a non-zero value
    /// otherwise.  The supported conversions are described in the
    /// `bdlat_symbolicconverter` component-level documentation.
    template <class LHS_TYPE, class RHS_TYPE>
    static int convert(LHS_TYPE        *lhs,
                       const RHS_TYPE&  rhs,
                       bsl::ostream&    errorStream);
    template <class LHS_TYPE, class RHS_TYPE>
    static int convert(LHS_TYPE *lhs, const RHS_TYPE&  rhs);
    static int convert(AnyRef lhs, AnyConstRef rhs, bsl::ostream& errorStream);
    static int convert(AnyRef lhs, AnyConstRef rhs);
};

// ============================================================================
//                              INLINE DEFINITIONS
// ============================================================================

                            // ------------------------
                            // struct SymbolicConverter
                            // ------------------------

template <class LHS_TYPE, class RHS_TYPE>
inline
int SymbolicConverter::convert(LHS_TYPE        *lhs,
                               const RHS_TYPE&  rhs,
                               bsl::ostream&    errorStream)
{
    return convert(bdlar::RefUtil::makeAnyRef(*lhs),
                   bdlar::RefUtil::makeAnyConstRef(rhs),
                   errorStream);
}

template <class LHS_TYPE, class RHS_TYPE>
inline
int SymbolicConverter::convert(LHS_TYPE *lhs, const RHS_TYPE& rhs)
{
    bsl::ostream nullStream(0);
    return convert(lhs, rhs, nullStream);
}

inline
int SymbolicConverter::convert(AnyRef lhs, AnyConstRef rhs)
{
    bsl::ostream nullStream(0);
    return convert(lhs, rhs, nullStream);
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2025 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
